#include "Triangle.h"

CTriangle::~CTriangle()
{
	delete m_A;
	delete m_B;
	delete m_C;
	delete m_NormalVector;
}

/*
	Method checks if ray intersects a triangle and returns way of intersection.

	Returns:
	0 - no intersection
	1 -	single point of intersection

	Method description:
	http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-9-ray-triangle-intersection/ray-triangle-intersection-geometric-solution/
*/
int	CTriangle::Intersect(CRay& _ray, IsectData &isectData)
{
/*
	float t = -1.0;
	CVector pointP;

	// Check case if the ray and the triangle are parallel...
	if ( FEQUAL(CVector::DotProduct( (*m_NormalVector), (*_ray.GetDirection())), 0.0f) ) 
		return 0;

	// Compute parametric 't'...
	t = GetParametricT(_ray);

	// Check if the triangle is behind the ray...
	if (t < 0.0f)
		return 0;

	// Compute the point on triangle plane...
	pointP = _ray.ParametricEquation(t);

	// Check if pointP is inside a triangle...
	CVector edgeAB = (*m_B) - (*m_A);
	CVector edgeBC = (*m_C) - (*m_B);
	CVector edgeCA = (*m_A) - (*m_C);
	CVector C0 = pointP - (*m_A);
	CVector C1 = pointP - (*m_B);
	CVector C2 = pointP - (*m_C);

	if ( CVector::DotProduct((*m_NormalVector), CVector::CrossProduct(edgeAB, C0)) > 0 && 
		 CVector::DotProduct((*m_NormalVector), CVector::CrossProduct(edgeBC, C1)) > 0 && 
		 CVector::DotProduct((*m_NormalVector), CVector::CrossProduct(edgeCA, C2)) > 0 )
		{
			_vecIntersec = pointP;
			return 1;
		}

	return 0;
*/
		CVector edge1 = *m_B - *m_A;
		CVector edge2 = *m_C - *m_A;
		CVector pvec = CVector::CrossProduct(*_ray.GetDirection(), edge2);
		float det = CVector::DotProduct(edge1, pvec);
		if (det == 0) return false;
		float invDet = 1 / det;
		CVector tvec = *_ray.GetOrigin() - *m_A;
		isectData.u = CVector::DotProduct(tvec, pvec) * invDet;
		if (isectData.u < 0 || isectData.u > 1) return false;
		CVector qvec = CVector::CrossProduct(tvec, edge1);
		isectData.v = CVector::DotProduct(*_ray.GetDirection(), qvec) * invDet;
		if (isectData.v < 0 || isectData.u + isectData.v > 1) return false;
		isectData.t = CVector::DotProduct(edge2, qvec) * invDet;

		return 1;
}

float CTriangle::GetParametricT(CRay& _ray)
{
	float retT = 0.0f;
	float D = CVector::DotProduct((*m_NormalVector), (*m_A));
	float numerator = CVector::DotProduct((*m_NormalVector), (*_ray.GetOrigin())) + D;
	float denominator = CVector::DotProduct((*m_NormalVector), (*_ray.GetDirection()));
	retT = - (numerator / denominator);

	return retT;
}

void CTriangle::ComputeNormal()
{
	m_NormalVector = new CVector( CVector::CrossProduct
					( 
						CVector(*m_B) - CVector(*m_A),
						CVector(*m_C) - CVector(*m_A)
					) );
}